package com.nuoniu.sibanyun.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nuoniu.sibanyun.common.exception.NuoNiuException;
import com.nuoniu.sibanyun.entity.SysCompany;
import com.nuoniu.sibanyun.entity.SysMenu;
import com.nuoniu.sibanyun.entity.SysRole;
import com.nuoniu.sibanyun.entity.SysRoleMenu;
import com.nuoniu.sibanyun.entity.bo.TreeUpdateBo;
import com.nuoniu.sibanyun.entity.crm.CrmGoods;
import com.nuoniu.sibanyun.entity.dto.MenuSaveDto;
import com.nuoniu.sibanyun.entity.dto.MenuSearchDto;
import com.nuoniu.sibanyun.entity.vo.AppUserMenuVo;
import com.nuoniu.sibanyun.entity.vo.AppUserModuleVo;
import com.nuoniu.sibanyun.entity.vo.RouterMenuVo;
import com.nuoniu.sibanyun.mapper.SysMenuMapper;
import com.nuoniu.sibanyun.service.ISysCompanyService;
import com.nuoniu.sibanyun.service.ISysMenuService;
import com.nuoniu.sibanyun.service.ISysRoleMenuService;
import com.nuoniu.sibanyun.service.ISysRoleService;
//import org.apache.commons.beanutils.BeanUtils;
import com.nuoniu.sibanyun.service.crm.ICrmGoodsService;
import com.nuoniu.sibanyun.userThread.UserInfo;
import com.nuoniu.sibanyun.userThread.UserThreadLocal;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单表 服务实现类
 * </p>
 *
 * @author baiqiang
 * @since 2020-04-23
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {

    @Autowired
    private SysMenuMapper sysMenuMapper;
    @Autowired
    private ISysRoleService sysRoleService;
    @Autowired
    private ISysRoleMenuService sysRoleMenuService;
    @Autowired
    private ISysCompanyService companyService;
    @Autowired
    private ICrmGoodsService goodsService;
    @Autowired
    private ICrmGoodsService crmGoodsService;

    @Override
    public List<SysMenu> listByUserId(Long userId) {
        List<SysMenu> sysMenus;
        if(1 == userId){
            QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("status",0);
            sysMenus = list(queryWrapper);
        }else{
            sysMenus = baseMapper.listByUserId(userId);
        }
        return sysMenus;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public SysMenu saveSysMenu(MenuSaveDto menuSaveDto,HttpServletRequest request) {
        if(null != menuSaveDto.getId() && null != menuSaveDto.getParentId() && menuSaveDto.getId().toString().equals(menuSaveDto.getParentId().toString())){
            throw new NuoNiuException("父级节点不能选择自己");
        }
        Integer userId = UserThreadLocal.get().getUserId();
        LocalDateTime dateTime = LocalDateTime.now();
        SysMenu oldMenu = null;
        SysMenu menu = new SysMenu();
        BeanUtils.copyProperties(menuSaveDto,menu);
        if(StringUtils.isBlank(menu.getSysCode())){
            menu.setSysCode("default");
        }
        if(null == menu.getTreeSort()){
            menu.setTreeSort(999);
        }
        Integer oldParentId = 0;
        if(null == menu.getId()){
            menu.setCreateDate(dateTime);
            menu.setCreateBy(userId);
            menu.setTreeLeaf(true);
        }else{
            oldMenu = getById(menu.getId());
            oldParentId = baseMapper.findParentId("sys_menu" ,menu.getId().intValue());
        }
        menu.setUpdateDate(dateTime);
        menu.setUpdateBy(userId);
        // 设置 所有父级编号、所有级别排序号
        if(null == menu.getParentId() || 0 == menu.getParentId()){
            menu.setParentId(0);
            menu.setParentIds(",0");
            menu.setTreeSorts(null == menu.getTreeSort() ? "" : "," + menu.getTreeSort().toString());
            menu.setTreeLevel(0);
            menu.setTreeNames("/" + menu.getMenuName());
        }else{
            SysMenu parentMenu = getById(menu.getParentId());
            if(null == parentMenu)throw new NuoNiuException("新父级节点不存在");
            menu.setParentIds(parentMenu.getParentIds() + ","+ menu.getParentId());
            menu.setTreeSorts(parentMenu.getTreeSorts() + "," + menu.getTreeSort());
            menu.setTreeLevel(parentMenu.getTreeLevel() + 1);
            menu.setTreeNames(parentMenu.getTreeNames() +"/"+ menu.getMenuName());
            if(null != oldParentId  && menu.getParentId().toString().equals(oldParentId.toString())){
                //不更新
                oldParentId = null;
            }else{

                //1.更新 新父节点TreeLeaf状态
                baseMapper.updateTreeLeafByState("sys_menu" , menu.getParentId(),0);

            }

        }

        saveOrUpdate(menu);
        //更新 老父节点的TreeLeaf状态
        if(null != oldParentId && 0 != oldParentId){
            baseMapper.updateTreeLeaf("sys_menu" , oldParentId);
        }
        if(null != menu.getId() && 0 != menu.getId()){

        }
        //如果当前节点不是节点，则更新当前节点的子节点树形数据
        if(null != oldMenu && !oldMenu.getTreeLeaf()){
            SysMenu newMenu = getById(menu.getId());
            TreeUpdateBo oldParentTree = new TreeUpdateBo();
            oldParentTree.setParentIds(oldMenu.getParentIds() + ",");
            oldParentTree.setTreeSorts(oldMenu.getTreeSorts() + ",");
            oldParentTree.setTreeNames(oldMenu.getTreeNames() + "/");
            TreeUpdateBo newParentTree = new TreeUpdateBo();
            newParentTree.setParentIds(newMenu.getParentIds() + ",");
            newParentTree.setTreeSorts(newMenu.getTreeSorts() + ",");
            newParentTree.setTreeNames(newMenu.getTreeNames() + "/");
            //计算等级差
            int levelDiff = newMenu.getTreeLevel() - oldMenu.getTreeLevel();
            baseMapper.updateChildrenTree("sys_menu" ,oldParentTree,newParentTree,levelDiff,menu.getId().intValue());


        }

        return menu;
    }


    /**
     * 删除 菜单信息
     * @param id
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean deleteSysMenu(Long id) {
        boolean haveChildrenMenus = baseMapper.isHaveChildrenMenus(id);
        if(haveChildrenMenus)throw new NuoNiuException("请删除当前菜单的子集菜单");
        QueryWrapper<SysRoleMenu> sysRoleMenuQueryWrapper = new QueryWrapper<>();
        sysRoleMenuQueryWrapper.eq("menu_id",id);
        int count = sysRoleMenuService.count(sysRoleMenuQueryWrapper);
        if(count > 0)throw new NuoNiuException("菜单权限已经分配了角色,请先解除关联关系");
        SysMenu sysMenu = getById(id);
        if(null == sysMenu){
            throw new NuoNiuException("删除失败，找不到该记录");
        }
        boolean b = removeById(id);
        //更新 父节点的TreeLeaf状态
        if(null != sysMenu.getParentId()){
            baseMapper.updateTreeLeaf("sys_menu" , sysMenu.getParentId());
        }
        return b;
    }

    /**
     * 批量更新 菜单排序（todo 维护子集的排序）
     * @param sysMenuList
     * @return
     */
    @Override
    public boolean batchUpdateTreeSorts(List<SysMenu> sysMenuList) {
        if(null == sysMenuList)return false;
        if(!sysMenuList.stream().allMatch(f -> null != f.getId() && null != f.getTreeSort())){
            throw new NuoNiuException("保存菜单：失败");
        }
        sysMenuList.stream().filter(f -> null != f.getId() && null != f.getTreeSort()).map(f->{
            SysMenu sysMenu = new SysMenu();
            sysMenu.setId(f.getId());
            sysMenu.setTreeSort(f.getTreeSort());
            return sysMenu;
        });
        boolean b = saveOrUpdateBatch(sysMenuList);
        return b;
    }


    @Override
    public List<RouterMenuVo> listRouterMenuVoByUserId(HttpServletRequest request) {
        UserInfo userInfo = UserThreadLocal.get();
        String userName = userInfo.getUserName();
        Integer userId = userInfo.getUserId();
        List<RouterMenuVo> routerMenuVoList = null;
        if("system".equals(userName)){
            routerMenuVoList = baseMapper.listRouterMenuVoBySystem();
        }else{
            Integer roleId = crmGoodsService.getCompanySysRoleIdByCompanyId();
            //获取租户 系统管理员角色 的菜单（为了解决 系统管理员角色 权限发生变动的一种处理方式）
            List<Long> adminRoleMenuIds = baseMapper.getMenuIdsByRoleId(roleId);
            //获取当前用户的菜单
            routerMenuVoList = baseMapper.listRouterMenuVoByUserId(Long.valueOf(userId));
            //过滤 菜单（目的是限定范围）
            routerMenuVoList = routerMenuVoList.stream().filter(menu->adminRoleMenuIds.contains(menu.getId())).collect(Collectors.toList());
            //如果停用,限制使用
            if(userInfo.getStatus() == 2){
                routerMenuVoList.stream().forEach(item->{
                    if(1 == item.getMenuType() && !"RouteView".equals(item.getComponent()) && !(item.getParentId() == 243 ||item.getId() == 243)){
                        item.setComponent("Limit");
                    }
                });
            }
        }
        return routerMenuVoList;
    }

    @Override
    public List<Long> getMenuIdsByRoleId(Integer id) {
        return baseMapper.getMenuIdsByRoleId(id);
    }

    /**
     * 通过userId 查询用户所有权限代码
     * @param userId
     * @return
     */
    @Override
    public String userPermissionString(Long userId) {
        String userPermission = "";
        List<SysRole> sysRoles = sysRoleService.listByUserId(userId);
        List<SysMenu> sysMenus = listByUserId(userId);
        //角色权限 需要在角色名前前缀"ROLE_"
        String roleListStr = sysRoles.stream().map(item->{
            String roleStr = "ROLE_" + item.getRoleName();
            return roleStr;
        }).collect(Collectors.joining(","));
        String menuListStr = sysMenus.stream().filter(f->StringUtils.isNotBlank(f.getPermission())).map(SysMenu::getPermission).collect(Collectors.joining(","));
        userPermission = roleListStr + "," + menuListStr;
        return userPermission;
    }

    @Override
    public Set<String> userPermissionList(Long userId) {
        Set<String> userPermission = new HashSet<>();
        List<SysRole> sysRoles = sysRoleService.listByUserId(userId);
        List<SysMenu> sysMenus = listByUserId(userId);
        //角色权限 需要在角色名前前缀"ROLE_"
        Set<String> roleListStr = sysRoles.stream().map(item->{
            String roleStr = "ROLE_" + item.getRoleName();
            return roleStr;
        }).collect(Collectors.toSet());
        Set<String> menuListStr = sysMenus.stream().filter(f->StringUtils.isNotBlank(f.getPermission())).map(SysMenu::getPermission).collect(Collectors.toSet());
        userPermission.addAll(roleListStr);
        userPermission.addAll(menuListStr);
        return userPermission;
    }

    @Override
    public Page<SysMenu> pageMenus(MenuSearchDto menuDto) {
        SysMenu sysMenu = new SysMenu();
        boolean isSearchLevelZero = true;
        QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>(sysMenu);
        if(null != menuDto.getParentId() && 0 != menuDto.getParentId()){
            queryWrapper.eq("parent_id",menuDto.getParentId());
            isSearchLevelZero = false;
        }
        if(StringUtils.isNotBlank(menuDto.getName())){
            queryWrapper.like("menu_name", menuDto.getName());
            isSearchLevelZero = false;
        }
        if(null != menuDto.getMenuType()){
            queryWrapper.eq("menu_type", menuDto.getMenuType());
            isSearchLevelZero = false;
        }
        if(isSearchLevelZero && !menuDto.getIsAll()){
            queryWrapper.eq("tree_level",0);
        }
        queryWrapper.eq("status", 0);
        queryWrapper.orderByAsc("tree_sort");
        Page page = page(menuDto.getPage(), queryWrapper);
        return page;
    }

    @Override
    public SysMenu getByUri(String uri) {
        return sysMenuMapper.getByUri(uri);
    }

    @Override
    public List<SysMenu> getByRole(Long id) {
        return sysMenuMapper.getByRoleList(id);
    }

    @Override
    public List<SysMenu> getAdminMenu(Long id) {
        UserInfo userInfo = UserThreadLocal.get();
        if(userInfo.getUserId() == 1) {
            return sysMenuMapper.getAllMenu();
        }

        SysCompany company = companyService.getById(userInfo.getCompanyId());
        if(company.getGoodsId() != null) {
            CrmGoods goods = goodsService.getById(company.getGoodsId());
            if(goods != null && goods.getRoleId() != null) {
                return sysMenuMapper.getByRoleMenu(goods.getRoleId());
            }
        }
        return sysMenuMapper.getByRoleMenu(2);
    }

    @Override
    public List<AppUserModuleVo> getAppUserModuleVoList() {
        List<AppUserModuleVo> appUserModuleVos = new ArrayList<>();
        HashMap<String,AppUserModuleVo> appUserModuleVoHashMap = new HashMap<>();
        UserInfo userInfo = UserThreadLocal.get();
        Integer roleId = crmGoodsService.getCompanySysRoleIdByCompanyId();
        //获取租户 系统管理员角色 的菜单（为了解决 系统管理员角色 权限发生变动的一种处理方式）
        List<Long> adminRoleMenuIds = baseMapper.getMenuIdsByRoleId(roleId);
        List<AppUserMenuVo> appUserMenuVos = baseMapper.listAppUserModuleVoByUserId(userInfo.getUserId().longValue());
        //过滤 菜单（目的是限定范围）
        appUserMenuVos = appUserMenuVos.stream().filter(menu->adminRoleMenuIds.contains(menu.getId())).collect(Collectors.toList());

        appUserMenuVos.forEach(menu->{
            String title = menu.getTitle();
            AppUserModuleVo appUserModuleVo = appUserModuleVoHashMap.get(title);
            if (null == appUserModuleVo){
                appUserModuleVo = new AppUserModuleVo();
                appUserModuleVo.setTitle(title);
                List<AppUserMenuVo> list = new ArrayList<>();
                appUserModuleVo.setList(list);
                appUserModuleVoHashMap.put(title,appUserModuleVo);
                appUserModuleVos.add(appUserModuleVo);
            }
            appUserModuleVo.getList().add(menu);
        });
        return appUserModuleVos;
    }

    @Override
    public SysMenu getByMenuPermission(String permission) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("permission", permission);
        wrapper.last("LIMIT 1");
        return this.getOne(wrapper);
    }


}
